package com.yxy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yxy.common.PageResult;
import com.yxy.constant.ExceptionConstant;
import com.yxy.constant.MessageConstant;
import com.yxy.constant.StatusConstant;
import com.yxy.domain.dto.UserDTO;
import com.yxy.domain.dto.UserLoginDTO;
import com.yxy.domain.dto.UserPageQueryDTO;
import com.yxy.domain.po.User;
import com.yxy.domain.vo.UserLoginVO;
import com.yxy.domain.vo.UserPageQueryVO;
import com.yxy.domain.vo.UserVO;
import com.yxy.exception.*;
import com.yxy.mapper.SignMapper;
import com.yxy.mapper.SportMapper;
import com.yxy.mapper.UserMapper;
import com.yxy.properties.AESProperties;
import com.yxy.properties.JwtProperties;
import com.yxy.service.SignService;
import com.yxy.service.SportService;
import com.yxy.service.UserService;
import com.yxy.utils.AESUtil;
import com.yxy.utils.JwtUtil;
import com.yxy.utils.QiniuOSSUtil;
import com.yxy.utils.SplitUtil;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AESProperties aesProperties;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private SignMapper signMapper;
    @Autowired
    private SportMapper sportMapper;

    /**
     * 注册
     * @param userDTO
     */
    @Override
    public void register(UserDTO userDTO) {
        String username = userDTO.getUsername().trim();
        String password = userDTO.getPassword().trim();
        String phone = userDTO.getPhone().trim();
        // 判断用户名是否存在
        User u = userMapper.getByUsername(userDTO.getUsername());
        if(u != null){
            throw new AccountAlreadyExistsException(MessageConstant.ACCOUNT_ALREADY_EXISTS);
        }

        User user = BeanUtil.copyProperties(userDTO, User.class);
        user.setUsername(username);
        user.setPhone(phone);

        // 加密
        try{
            user.setPassword(AESUtil.encrypt(password, aesProperties.getSecretKey()));
        } catch (Exception e) {
            throw new ServerException(ExceptionConstant.SERVER_ERROR);
        }
        user.setStatus(StatusConstant.ENABLE);
        user.setCreateTime(LocalDateTime.now());
        userMapper.insert(user);
    }

    /**
     * 登录
     * @param userLoginDTO
     * @return
     */
    @SneakyThrows
    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        // 查询用户是否存在
        User user = userMapper.getByUsername(userLoginDTO.getUsername());
        if(user == null){
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        // 判断状态
        if(user.getStatus() == StatusConstant.DISABLE){
            throw new AccountDisabledException(MessageConstant.ACCOUNT_DISABLED);
        }
        // 判断密码
        if (!user.getPassword().equals(AESUtil.encrypt(userLoginDTO.getPassword(), aesProperties.getSecretKey()))) {
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }
        // 验证通过
        UserLoginVO vo = BeanUtil.copyProperties(user, UserLoginVO.class);
        // 生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("u_id", user.getId());
        String token = JwtUtil.createJwt(jwtProperties.getUserSecretKey(), jwtProperties.getUserExpire(), claims);
        vo.setToken(token);
        return vo;
    }

    /**
     * 校验密码
     * @param password
     */
    @SneakyThrows
    @Override
    public void verifyPwd(Integer id, String password) {
        // 查询用户
        User user = userMapper.getById(id);
        if(user == null){
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        if(!user.getPassword().equals(AESUtil.encrypt(password, aesProperties.getSecretKey()))){
            throw new PasswordErrorException(MessageConstant.ORIGIN_PASSWORD_ERROR);
        }
    }

    /**
     * 修改密码
     * @param id
     * @param newPwd
     */
    @Override
    public void updatePwd(Integer id, String newPwd) {
        // 密码加密
        try{
            newPwd = AESUtil.encrypt(newPwd, aesProperties.getSecretKey());
        } catch (Exception e) {
            throw new ServerException(ExceptionConstant.SERVER_ERROR);
        }
        userMapper.updatePwd(id, newPwd);
    }

    /**
     * 校验手机号
     * @param id
     * @param phone
     */
    @Override
    public void verifyPhone(String username, String phone) {
        // 判断用户是否存在
        User user = userMapper.getByUsername(username);
        if(user == null){
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        // 判断手机号是否正确
        if(!user.getPhone().equals(phone)){
            throw new PhoneErrorException(MessageConstant.PHONE_ERROR);
        }
    }

    /**
     * 重置密码
     * @param userDTO
     */
    @Override
    public void resetPwd(UserDTO userDTO) {
        try{
            userDTO.setPassword(AESUtil.encrypt(userDTO.getPassword(), aesProperties.getSecretKey()));
        } catch (Exception e) {
            throw new ServerException(ExceptionConstant.SERVER_ERROR);
        }
        userMapper.resetPwd(userDTO.getUsername(), userDTO.getPassword());
    }

    /**
     * 获取用户信息
     * @param id
     * @return
     */
    @Override
    public UserVO getUserInfo(Integer id) {
        User user = userMapper.getById(id);
        if(user == null){
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        return BeanUtil.copyProperties(user, UserVO.class);
    }

    /**
     * 修改用户信息
     * @param userDTO
     */
    @Override
    public void updateUserInfo(UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        String originalAvatar = userDTO.getOriginalAvatar();
        if(originalAvatar!= null){
            // 从七牛云删除原有资源
            QiniuOSSUtil.deleteFileFromQiniu("sports/" + SplitUtil.split(originalAvatar));
        }
        userMapper.update(user);
    }

    /**
     * 修改活动时间
     * @param id
     */
    @Override
    public String modifyActivityTime(Integer id) {
        // 查询当前用户状态
        User user = userMapper.getById(id);
        if(user == null){
            return StatusConstant.ACCOUNT_NOT_FOUND;
        }
        if(user.getStatus() == StatusConstant.DISABLE){
            return StatusConstant.DISABLE_STATUS;
        }
        userMapper.modifyActivityTime(id, LocalDateTime.now());
        return "";
    }

    /**
     * 分页查询
     * @param param
     * @return
     */
    @Override
    public PageResult page(UserPageQueryDTO userPageQueryDTO) {
        PageHelper.startPage(userPageQueryDTO.getPage(), userPageQueryDTO.getPageSize());
        Page<UserPageQueryVO> page = userMapper.page(userPageQueryDTO);
        page.getResult().forEach(item -> {
            // 密码解密
            try{
                item.setPassword(AESUtil.decrypt(item.getPassword(), aesProperties.getSecretKey()));
            }catch (Exception e){
                throw new ServerException(ExceptionConstant.SERVER_ERROR);
            }
        });
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 修改状态
     * @param id
     * @param status
     */
    @Override
    public void state(int id, int status) {
        userMapper.updateState(id, status);
    }

    /**
     * 批量删除
     * @param ids
     */
    @Transactional
    @Override
    public void batchDelete(List<Integer> ids) {
        userMapper.deleteByIds(ids);
        // 删除用户相关的运动信息
        // 删除打卡信息
        signMapper.deleteByUserIds(ids);
        // 删除运动信息
        // 先查询中要删除的运动信息的id
        List<Integer> sportIds = sportMapper.selectIdsByUserIds(ids);
        // 删除运动信息
        sportMapper.deleteByUserIds(ids);
        // 根据运动id删除运动数据列表
        sportMapper.deleteSportListBySportIds(sportIds);
    }
}
